package tcp28175

import (
	"bytes"
	"fmt"
	"github.com/dubbogo/gost/log/logger"
	api "iotall/iottest/entity"
	"math/rand"
	"net"
	"strings"
	"time"
)

type Client struct {
	Ip   string
	Port int

	Druation int
	Id       []byte
	conn     *net.TCPConn
	revbuf   *[]byte
	xtbuf    *[]byte
	lstdt    time.Time
	seqno    int
}

func (p *Client) Start() {
	go p.Run()
}

func (p *Client) read(timeout time.Time) ([]byte, int, error) {

	buf := *p.revbuf
	p.conn.SetReadDeadline(timeout)
	n, err := p.conn.Read(buf)
	if err != nil {

		return nil, 0, err
	}
	if n == 0 {

		return nil, 0, nil
	}
	if n == len(buf) {
		//继续读取
		var buffw bytes.Buffer
		buffw.Write(buf)
		for {
			p.conn.SetReadDeadline(time.Now().Add(1))
			n, err = p.conn.Read(buf)
			if err != nil {
				if ope, ok := err.(*net.OpError); ok {
					if strings.Index(ope.Error(), "i/o timeout") >= 0 {
						break
					}
				}

				return nil, 0, err
			}
			buffw.Write(buf[:n])
			if n < len(buf) {
				break
			}
		}
		return buffw.Bytes(), buffw.Len(), nil
	}

	return buf, n, nil
}
func (p *Client) buildCmd07() {
	var pbuf []byte
	if p.xtbuf == nil {
		pbuf = make([]byte, 30)
		pbuf[0] = 0x40
		pbuf[1] = 0x40

		pbuf[4] = 0x4
		pbuf[5] = 0x5

		pbuf[12] = p.Id[5]
		pbuf[13] = p.Id[4]
		pbuf[14] = p.Id[3]
		pbuf[15] = p.Id[2]
		pbuf[16] = p.Id[2]
		pbuf[17] = p.Id[0]

		pbuf[26] = 0x07
		pbuf[28] = 0x23
		pbuf[29] = 0x23
		p.xtbuf = &pbuf
	} else {
		pbuf = *p.xtbuf
	}

	var seqnoH byte = byte(p.seqno / 256)
	var seqnoL byte = byte(p.seqno % 256)
	pbuf[2] = seqnoL
	pbuf[3] = seqnoH

	p.seqno++
	if p.seqno > 256*256 {
		p.seqno = 1
	}
	var dt = time.Now()
	pbuf[6] = byte(dt.Second())
	pbuf[7] = byte(dt.Minute())
	pbuf[8] = byte(dt.Hour())
	pbuf[9] = byte(dt.Day())
	pbuf[10] = byte(dt.Month())
	pbuf[11] = byte(dt.Year() - 2000)

}
func (p *Client) buildCmd03(seqno int32) *[]byte {
	var pbuf = make([]byte, 30)

	pbuf[0] = 0x40
	pbuf[1] = 0x40

	pbuf[4] = 0x4
	pbuf[5] = 0x5

	pbuf[12] = p.Id[5]
	pbuf[13] = p.Id[4]
	pbuf[14] = p.Id[3]
	pbuf[15] = p.Id[2]
	pbuf[16] = p.Id[2]
	pbuf[17] = p.Id[0]

	pbuf[26] = 0x03
	pbuf[28] = 0x23
	pbuf[29] = 0x23

	var seqnoH byte = byte(seqno / 256)
	var seqnoL byte = byte(seqno % 256)
	pbuf[2] = seqnoL
	pbuf[3] = seqnoH

	var dt = time.Now()
	pbuf[6] = byte(dt.Second())
	pbuf[7] = byte(dt.Minute())
	pbuf[8] = byte(dt.Hour())
	pbuf[9] = byte(dt.Day())
	pbuf[10] = byte(dt.Month())
	pbuf[11] = byte(dt.Year() - 2000)
	return &pbuf
}

func (p *Client) write(data *[]byte) error {
	_, err := p.conn.Write(*data)

	return err
}
func (p *Client) write03(seqno int32) error {
	var data = p.buildCmd03(seqno)
	_, err := p.conn.Write(*data)

	return err
}
func (p *Client) writeXt() error {
	p.buildCmd07()
	_, err := p.conn.Write(*p.xtbuf)

	return err
}

func (p *Client) Run() {

	socket, err := net.DialTCP("tcp", nil, &net.TCPAddr{
		IP:   net.ParseIP(p.Ip),
		Port: p.Port})
	if err != nil {
		logger.Error("err:", err)
		return
	}

	api.AddConnOk(1)
	defer func() {
		if err2 := recover(); err2 != nil {
			fmt.Println(err2)
		}
		api.AddConnOk(-1)

		socket.Close() //关闭连接
	}()
	p.conn = socket
	var pbuf = make([]byte, 1024)
	p.revbuf = &pbuf
	p.lstdt = time.Now().AddDate(1, 0, 0)
	p.seqno = 1

	var buf []byte
	var n int
	for i := 0; ; i++ {
		if i == 0 ||
			time.Since(p.lstdt) > time.Duration(api.GloabSetting.HeathDuration)*time.Second {
			var d = rand.Intn(5)
			time.Sleep(time.Duration(d) * time.Second)
			err = p.writeXt()
			if err != nil {
				logger.Error("发送数据失败", err)
				return
			}
			api.AddXtUp(1)

			p.lstdt = time.Now()

			buf, n, err = p.read(time.Now().Add(time.Duration(api.GloabSetting.ServerConfirmTimeout) * time.Second))
			if err != nil {

				continue
			}
		} else {
			buf, n, err = p.read(time.Now().Add(time.Duration(api.GloabSetting.HeathDuration*1) * time.Second))
			if err != nil {
				if strings.Index(err.Error(), "timeout") >= 0 {
					continue
				} else {

					return
				}
			}
		}

		if n > 0 {
			var data = buf[:n]
			//	var msg = fmt.Sprintf("%x", data)

			var gwups = p.Splits(&data)
			for _, v := range *gwups {
				if !v.Check {
					return //数据不合法
				}
				switch v.Cmd {
				case 0x07:
					api.AddXtBack(1)

					break
				case 0x01:
					fmt.Printf("\r\n设置时间：：：：：：\r\n")
					api.AddServerCmd(1)
					fmt.Printf("NO:%v \r\n", v.SeqNo)
					err = p.write03(v.SeqNo)
					if err != nil {
						logger.Error("发送数据失败", err)
						return
					}
					api.AddServerCmdConfirm(1)
					break
				case 0x08: //重启
					api.AddServerCmd(1)
					fmt.Printf("\r\n重启：：：：：：\r\n")
					err = p.write03(v.SeqNo)
					if err != nil {
						logger.Error("发送数据失败", err)
						return
					}
					api.AddServerCmdConfirm(1)
					//重启
					go func() {
						logger.Info("\r\n重启等待中\r\n", err)
						time.Sleep(2 * time.Second)
						p.Run()
					}()
					return //关闭
				}

			}

		} else {
			p.conn.Close()
		}
	}

}

func (c *Client) Splits(data *[]byte) *[]api.GwUp {
	var r = make([]api.GwUp, 0)
	//40 40 47 BD 0B 02 0F 24 0E 1A 02 18 00 00 00 00 00 00 01 00 00 00 00 00 00 00 07 8E 23 23
	for index := 0; index < len(*data); {
		var gwup = c.Split(data, index)
		if gwup.Check {
			r = append(r, *gwup)
			index += len(gwup.Data)
		} else {
			r = make([]api.GwUp, 0)
			r = append(r, *gwup)
			break
		}
	}
	return &r
}
func (c *Client) Split(data *[]byte, index int) *api.GwUp {
	var r = &api.GwUp{
		SeqNo:    0,
		Ver:      "",
		Dt:       "",
		Gw:       "",
		Len:      0,
		Cmd:      0,
		Data:     nil,
		Check:    false,
		CheckErr: "",
	}
	//40 40 47 BD 0B 02 0F 24 0E 1A 02 18 00 00 00 00 00 00 01 00 00 00 00 00 00 00 07 8E 23 23
	if index+30 > len(*data) {
		r.CheckErr = "长度不够"
		r.Data = *data
		return r
	}
	r.Len = int32(256) * int32((*data)[index+25])
	r.Len += int32((*data)[index+24])
	r.Data = (*data)[index : index+30+int(r.Len)]
	if 0x40 != r.Data[0] || 0x40 != r.Data[1] {
		r.CheckErr = "协议头错误"
	}
	if 0x23 != r.Data[len(r.Data)-1] || 0x23 != r.Data[len(r.Data)-2] {
		r.CheckErr = "协议尾错误"
	}

	r.SeqNo = int32(256) * int32(r.Data[3])
	r.SeqNo += int32(r.Data[2])

	r.Ver = fmt.Sprintf("%v.%v", r.Data[5], r.Data[4])

	r.Dt = fmt.Sprintf("20%v-%v-%v %v:%v:%v", r.Data[11], r.Data[10], r.Data[9], r.Data[8], r.Data[7], r.Data[6])

	r.Gw = fmt.Sprintf("%v.%v.%v.%v.%v.%v", r.Data[17], r.Data[16], r.Data[15], r.Data[14], r.Data[13], r.Data[12])

	r.Cmd = int32(r.Data[26])

	r.Check = true
	return r
}
